//
//  ZDevice.h
//  Part of Z-Way.C library
//
//  Created by Alex Skalozub on 1/30/12.
//  Based on Z-Way source code written by Christian Paetz and Poltorak Serguei
//
//  Copyright (c) 2012 Z-Wave.Me
//  All rights reserved
//  info@z-wave.me
//
//  This source file is subject to the terms and conditions of the
//  Z-Wave.Me Software License Agreement which restricts the manner
//  in which it may be used.
//

#ifndef zway_device_h
#define zway_device_h

#include "ZWayTimerPrivate.h"

// libS2 context
struct _ZDeviceS2
{
    struct S2 *ctx;
    _ZTimer_t *timer;
    _ZTimer_t *s2_inclusion_timer;
    ZJob current_job;
};

struct _ZDevice
{
    ZWNODE id;
    ZDataHolder data;
    ZInstanceList instances;
    ZInstance default_instance;
    
    // PowerLevel data:
    ZWNODE powerlevel_requested_node_id;
    ZWNODE powerlevel_originator_node_id;
    ZWBYTE powerlevel_power;
    ZWBOOL powerlevel_status;
    uint16_t powerlevel_total_count;
    uint16_t powerlevel_sent_count;
    uint16_t powerlevel_successful_count;
    
    // Inclusion timer:
    float inclusion_timer;
    _ZTimer_t *zway_as_sis_waiting_for_inclusion_controller_timer;
    
    // last sent job
    ZJob last_sent;

    // Deviec specific libS2 context
    ZDeviceS2 s2;
};

// deallocate a device pointer and free all associated resources
void _zway_device_free(const ZWay zway, ZDevice device);

// create a new device object
// NULL == allocation error
ZDevice _zway_device_create(const ZWay zway, ZWNODE id, ZWBOOL add_node_network);

// Create dummy device - used for PowerLevel CC to unknown node
ZDevice _zway_device_create_dummy(const ZWay zway);

void _zway_device_attach_callbacks(const ZWay zway, ZDevice device);

// creates a new instance for specified device
ZInstance _zway_device_add_instance(const ZWay zway, ZDevice device, ZWBYTE id);

// returns an instance by identifier for specified device
ZInstance _zway_device_get_instance(const ZWay zway, ZDevice device, ZWBYTE id);

// deletes non-default instances and command classes from device
void _zway_device_purge_instances_and_command_classes(const ZWay zway, ZDevice device);

// loads command classes for device
void _zway_device_load_command_classes(const ZWay zway, ZDevice device);

// checks if interview is done for every command of each instance
ZWBOOL _zway_device_is_interview_done(const ZWay zway, const ZDevice device);

// checks if interview failed for at least one command on some instance
ZWBOOL _zway_device_is_interview_failed(const ZWay zway, const ZDevice device);

// invalidates an interview for device
void _zway_device_interview_invalidate(const ZWay zway, ZDevice device);

// starts an interview for device
void _zway_device_interview(const ZWay zway, ZDevice device);
void _zway_device_interview_force(const ZWay zway, ZDevice device);

// interview steps
void _zway_device_interview_step1(const ZWay zway, ZDevice device, ZWBOOL previous_skipped);
void _zway_device_interview_step2(const ZWay zway, ZDevice device, ZWBOOL previous_skipped);
void _zway_device_interview_step3(const ZWay zway, ZDevice device, ZWBOOL previous_skipped);
void _zway_device_interview_step4(const ZWay zway, ZDevice device, ZWBOOL previous_skipped);
void _zway_device_interview_step5(const ZWay zway, ZDevice device, ZWBYTE instanceId, ZWBOOL previous_skipped);

// interview finished for device
void _zway_device_interview_finished(const ZWay zway, ZDevice device);

// interview failed for device
void _zway_device_interview_failed(const ZWay zway, ZDevice device);

// set version of CCs on an instance and tells if successful or Version Command Class Get is required to get the version
ZWBOOL _zway_set_instance_command_classes_version(ZWay zway, ZInstance instance);

void _zway_device_awake_queue(const ZWay zway, ZDevice device, ZWBOOL broadcastAwake);

void _zway_device_mark_sleeping(const ZWay zway, ZDevice device);

ZWBOOL _zway_device_remove_wakeup_no_more_info(const ZWay zway, ZDevice device);
void _zway_device_remove_security_s2_nonce_get_without_callback(const ZWay zway, ZDevice device);


// set lastSendInternal
void _zway_device_delay_communication(ZWay zway, ZDevice device, int delay);

void _zway_device_assign_return_route(const ZWay zway, ZDevice device, ZWNODE node_id);
void _zway_device_delete_return_route(const ZWay zway, ZDevice device);
void _zway_device_assign_suc_return_route(const ZWay zway, ZDevice device);
void _zway_device_delete_suc_return_route(const ZWay zway, ZDevice device);

ZWError _zway_device_send_nop(const ZWay zway, ZDevice device, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZCommand _zway_device_render_command_class_internal(const ZWay zway, ZDevice device, ZInstance instance, ZWBYTE cc_id);
ZCommand _zway_device_render_command_class(const ZWay zway, ZDevice device, ZWBYTE instance_id, ZWBYTE cc_id);
void _zway_device_render_command_classes(const ZWay zway, ZDevice device, ZWBYTE instance_from, ZWBYTE instance_to, const ZWBYTE *cc_mask);
void _zway_device_load_controlled_command_classes_from_nif(const ZWay zway, ZDevice device);
void _zway_device_render_controlled_command_classes_from_zddx(const ZWay zway, ZDevice device, ZWBYTE *cc_mask);
void _zway_device_render_controlled_command_classes(const ZWay zway, ZDevice device, const ZWBYTE *cc_mask);

// Load XML file to the ZDDX and create all Command Classes
ZWError _zway_device_load_xml(const ZWay zway, ZDevice device, ZWCSTR file_name);

ZWError _zway_device_get_configuration(const ZWay zway, ZDevice device);

// Automatically chooses ZDDX file for device (if possible)
ZWError _zway_device_choose_xml(const ZWay zway, ZDevice device);

// Erase NIF and as for the NIF again
ZWError zway_device_reask_nif(ZWay zway, ZDevice device);

// Don't erase NIF and don't run full interview, just create Inclusion Controller CC
ZWError zway_device_ask_nif_and_render_inclusion_controller_cc(ZWay zway, ZDevice device);

// Prepare for secure and normal interview
void _zway_prepare_first_communication_after_inclusion(ZWay zway, ZDevice device, ZWBOOL informed_as_sis);

// Set given name
void _zway_device_set_default_given_name(ZWay zway, ZDevice device);
void _zway_device_set_given_name_by_key(ZWay zway, ZDevice device, size_t dskLen, const ZWBYTE *dsk);

// CC mask functions
void _zway_cc_mask_clear(ZWay zway, ZWBYTE cc_mask[32]);
void _zway_cc_mask_fill(ZWay zway, ZWBYTE cc_mask[32], const ZWBYTE* supported_cmd_list, size_t supported_cmd_list_length);
void _zway_cc_mask_add(ZWay zway, ZWBYTE cc_mask[32], ZWBYTE ccId);
void _zway_cc_mask_remove(ZWay zway, ZWBYTE cc_mask[32], ZWBYTE ccId);
ZWBOOL _zway_cc_mask_is_set(ZWay zway, const ZWBYTE cc_mask[32], ZWBYTE ccId);

ZJob _zway_device_get_last_job(ZDevice device);
void _zway_device_set_last_job(ZDevice device, const ZJob job);
void _zway_device_clear_last_job(const ZWay zway, const ZJob job);

#endif
